An automated email, SMS and AI phone-calling system that works your dead CRM leads for you — and hands you back the ones that are ready to talk. Import two blueprints, connect five accounts, go live.
Every broker is sitting on a graveyard. Hundreds — often thousands — of people who once enquired about finance, never converted, and have not been contacted since.
This system goes back through them, one at a time, and restarts the conversation. It writes a personal email in your voice, follows up by SMS, and for the highest-intent leads it puts through an AI phone call. When someone replies, a second scenario reads the reply, works out what they meant, and either books them in, parks them, or removes them permanently.
You do not build any of it by hand. The two scenarios ship as blueprint files: upload a JSON file, connect your accounts, and the whole engine appears on the canvas already wired.
One sends. One listens. Both included in this pack, ready to upload.
Your CRM, OpenAI, your mailbox, your SMS provider, and Retell AI for the calls.
Roughly seven Make operations plus a fraction of a cent of OpenAI per lead contacted.
The engine is CRM-agnostic. Only the first module and the last module touch your CRM — everything in between is identical no matter what you run. That is why one product covers the whole market.
Closed platforms will not let an automation read them directly. So you export your dormant leads to a Google Sheet — a five-minute job you repeat monthly — and the engine reads the sheet instead of the CRM. Everything downstream is untouched: same AI, same email, same SMS, same AI call, same reply triage. The only thing you lose is the automatic write-back, which you replace with a second sheet the engine fills in and you re-import.
API access to aggregator-owned platforms is granted by the aggregator, not the broker, and the answer differs by group and sometimes by brokerage. Confirm access is available for a given account before quoting a native build — and default to the bridge method, which works everywhere without anyone's permission.
Eight modules, one router, three channels. This is exactly what the blueprint builds.
The engine stores its campaign state on the contact record. Two custom Contact properties carry it, and everything else in this guide assumes they exist. Create them before you import anything, or the HubSpot modules will show as invalid.
In HubSpot go to Settings → Properties → Create property, object type Contact, and add these two. Use the internal names exactly as written — the blueprints are mapped to them.
Why this matters more than it looks. tbt_reactivation_state = opt_out is the suppression flag. When somebody replies STOP, workflow 2 writes that value, and the consent gate on the outbound side refuses to pass any contact carrying it. That is the entire opt-out mechanism. Without these two properties there is nothing stopping the engine contacting someone who has already asked you not to.
This system contacts real people who gave you their details, and only those people. It is not a cold-outreach tool and must never be pointed at a purchased list. Every message carries an opt-out, and the opt-out is honoured automatically and permanently.
Import first, then connect. Do not build this by hand; the blueprint already contains every prompt, filter and mapping.
The whole engine appears at once — nine modules, the router, all three filters and every prompt already written. Every module will show a small warning triangle because it has no connection yet. That is expected and is what step 2 fixes.
Make refuses blueprints that reference an app your account has not installed. Open the file, confirm it is valid JSON (no stray characters if you opened it in a text editor), and check that HubSpot CRM, OpenAI and your SMS app all appear when you search for them in Make. Install any that do not.
Click each module in turn. Where it says Connection, click Add and sign in. Work left to right.
| Module | App | What it needs |
|---|---|---|
| 1 · Search Contacts | HubSpot CRM | OAuth sign-in to your portal |
| 2 · Create Completion | OpenAI | Your API key, pasted into the API Key field |
| 5 · Send an Email | Gmail | OAuth sign-in — pick the mailbox replies should land in |
| 6 · Make an API Call | HubSpot CRM | Re-use the connection from module 1 |
| 7 · Send SMS | Your SMS provider | API key and secret from the provider's dashboard |
| 8 · HTTP request | Retell AI | No connection — paste your key into the Authorization header |
When you connect Gmail, Make asks for a Google connection with send permission. Grant it — without it module 5 fails silently at run time with a permissions error that is easy to misread as a mapping problem.
Open module 1 · Search Contacts. The blueprint ships with an empty query and a limit of 25. Two things to set:
If HubSpot search filters give you trouble, build a static list in HubSpot called Dormant Leads — Reactivation, then swap module 1 for HubSpot → Get a List's Contacts. Same result, and you can eyeball exactly who is in the campaign before it runs.
Open module 2 · Create Completion. It contains two messages. The system message is the rulebook — leave the compliance rules alone, but adjust the tone if you want. The user message is the lead's file, and it contains three things you must change:
Broker business name: [YOUR BUSINESS NAME] Broker first name: [YOUR FIRST NAME] Opt-out wording for SMS: Reply STOP to opt out.
The prompt already forces the model to return a clean JSON object with five fields, which is why module 3 can split it into a subject, an email body, an SMS and a call opening line without any extra work:
{
"email_subject": "...",
"email_body_html": "...",
"sms_text": "...",
"call_opening_line": "...",
"priority": "HIGH" | "MEDIUM" | "LOW"
}
The AI reads the lead's history and scores their likely intent. Module 8 only fires when that score comes back HIGH, so your AI phone calls — the expensive channel — are spent on the leads most likely to answer. Change the filter on module 8 to HIGH or MEDIUM if you want more volume.
Three quick fields across the three router branches:
| Module | Field | Set it to |
|---|---|---|
| 5 · Send an Email | From | Your name and sending address, e.g. Matt at Broker Times <matt@yourdomain.com.au> |
| 7 · Send SMS | From | Your registered sender ID or virtual number. Leave blank to use the account default. |
| 8 · HTTP request | Headers & body | Replace YOUR_RETELL_API_KEY, YOUR_RETELL_NUMBER and YOUR_RETELL_AGENT_ID with the values from your Retell dashboard. |
Everything else — the recipient, the subject, the message body, the SMS text, the call script variables — is already mapped from the AI output. Do not re-map them.
You should receive an email and a text within a minute, and see a new note on your HubSpot contact. Read the email properly. If the tone is not yours, go back to module 2 and adjust the system message — that is where the voice lives.
Set the schedule to Every day at 09:30, put the limit back to 25, restore your real dormant filter, and switch the scenario ON.
Scenario 1 starts conversations. This one is where the money is: it reads every reply and decides what happens next, in seconds, at any hour of the night.
Same process: new scenario → … → Import Blueprint → 02-TBT-Reply-Triage-HubSpot.blueprint.json.
You get a webhook trigger, an AI classifier, and a four-branch router: HOT, WARM, NOT NOW and OPT OUT.
{
"contact_id": "HubSpot contact ID",
"first_name": "Sarah",
"email": "sarah@example.com.au",
"mobile": "+61400000000",
"channel": "sms" | "email" | "call",
"message": "the exact words they replied with"
}
Send one test POST with that shape, and Make will learn the data structure automatically.
| Branch | What fires | What you should change |
|---|---|---|
| HOT | Creates a HubSpot deal and emails you the reply plus the AI's suggested next action | Set the alert email address and your pipeline's first stage ID |
| WARM | Lead status stays OPEN, writes tbt_reactivation_state = warm and stamps today's date | Point it at your nurture list if you run one |
| NOT NOW | Lead status stays OPEN, writes tbt_reactivation_state = not_now and stamps today's date so your dormancy rule skips them for 90 days | Change 90 days to whatever suits your book, in module 1's filter |
| OPT OUT | Writes tbt_reactivation_state = opt_out and sets lead status UNQUALIFIED. Both are conditions on the consent gate, so this contact can never be selected again | Nothing. Do not weaken this branch |
The OPT OUT branch does not delete anybody and it does not touch HubSpot's own hs_email_optout property, which the API cannot write to. It sets tbt_reactivation_state to opt_out, and the consent gate in scenario 1 refuses to pass any contact carrying that value. The SMS and phone branches re-check it independently, so a suppression cannot leak through the router.
This is why the two custom properties are not optional. If tbt_reactivation_state does not exist, this branch writes nothing and the gate has nothing to read.
POST a test payload where message is just “STOP”, confirm it takes the OPT OUT branch, then open the contact in HubSpot and check tbt_reactivation_state now reads opt_out. Then run scenario 1 again and confirm that contact is not picked up a second time. That last step is the one that matters.
Roughly 5,250 Make operations, a few dollars of OpenAI, plus whatever your SMS provider charges per message and Retell charges per call minute. The leads themselves cost nothing — they are already sitting in your CRM. Run your first batch, measure your own reply rate, and use those numbers from then on rather than anybody's claimed averages.
| Symptom | Cause | Fix |
|---|---|---|
| Module 3 errors on Parse JSON | The model wrapped its answer in a code fence | Confirm Response format on module 2 is set to json_object |
| Scenario runs, sends nothing | The consent filter on module 2 is blocking everything | Click the filter bubble in History — it shows exactly which condition failed |
| Email module fails with 403 | Gmail connection lacks send scope | Delete the connection and re-add it, accepting all requested permissions |
| SMS branch never runs | Mobile numbers stored in phone, not mobilephone | Edit the filter on module 7 to match your CRM's actual field |
| Retell returns 401 | Missing the word Bearer | The header value must read Bearer sk-..., with the space |
| Operations burning fast | Limit set too high, or scenario scheduled every 15 minutes | Daily schedule, limit 25. That is up to 750 leads a month on roughly 5,000 operations. |
| Webhook never fires | Scenario 2 is switched off, or the URL was pasted with a trailing space | Turn it on, re-copy the URL, send a test POST |
The same engine, configured against your CRM, your voice and your compliance settings — installed and tested, with the first batch running before you hang up.
Talk to The Broker Times